﻿namespace AzureCamp.Table.RssAggregatorBusiness
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Services.Client;
    using System.Linq;
    using Microsoft.Samples.ServiceHosting.StorageClient;
    using System.Net;
    using AzureCamp.RssAggregatorBusiness.Queue;
    using AzureCamp.RssAggregatorBusiness;
    using AzureCamp.RssAggregatorBusiness.Constants;

    public class RSSAggregatorContext : TableStorageDataServiceContext
    {
        private QueueDeleteBlob queue = new QueueDeleteBlob();
        public IQueryable<Feed> Feeds
        {
            get
            {
                return this.CreateQuery<Feed>(TableName.Feeds);
            }
        }

        public IQueryable<RssLink> Urls
        {
            get
            {
                return this.CreateQuery<RssLink>(TableName.Urls);
            }
        }

        public RSSAggregatorContext():this(StorageAccountInfo.GetAccountInfoFromConfiguration("TableStorageEndpoint"))
        {
        }

        public RSSAggregatorContext(StorageAccountInfo accountInfo)
            : base(accountInfo)
        {

        }

        public void AddFeed(Feed f)
        {
            if (FeedsContains(f))
            {
                return;
                
            }
            this.AddObject(TableName.Feeds, f);
            foreach (RssLink r in f.GetUrls())
            {
                this.AddRss(r);
            }

            this.SaveChanges();
        }

        public bool RemoveFeed(string category, string feedName)
        {
            try
            {
                var feed = (from f in Feeds
                              where f.Title.Equals(feedName)
                              & f.Category.Equals(category)
                              select f).FirstOrDefault();

                
                if (feed!=null)
                {
                    RemoveRss(feed.RowKey);
                    this.DeleteObject(feed);
                    
                    queue.PutDeleteBlobInWaitList(feed.Category + ":" + feed.Title);
                }

                this.SaveChanges();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public void RemoveRss(string feedholder)
        {
            var result = from url in Urls
                         where url.FeedHolder.Equals(feedholder)
                         select url;
            IEnumerable<RssLink> links = ProcessRssLinkQuery(result);
            foreach(RssLink link in links)
                this.DeleteObject(link);
            this.SaveChanges();
        }



        private void AddRss(RssLink rssLink)
        {
            //bool doesContain = LinksContains(rssLink);
            //if(doesContain==null) return;
            //if (!doesContain)
            try
            {
                this.AddObject(TableName.Urls, rssLink);
            }
            catch
            {
            }
        }

        public bool LinksContains(RssLink rssLink)
        {
            var result = (from r in Urls
                          where (r.FeedHolder == rssLink.FeedHolder)
                          & (r.Url == rssLink.Url)
                          select r).FirstOrDefault();
            return result != null;
            //return ProcessRssLinkQuery(result).Count() > 0;
        }

        public bool FeedsContains(Feed feed)
        {
            var result = (from f in Feeds
                          where f.Owner == feed.Owner &
                          f.Title == feed.Title
                          select f).FirstOrDefault();
            return result != null;
            //return ProcessFeedsQuery(result).Count() > 0;
        }

        public IEnumerable<RssLink> GetRssLinks(string feedholderRowKey)
        {
            var result = from u in Urls
                         where u.FeedHolder==feedholderRowKey
                         select u;

            IEnumerable<RssLink> links = ProcessRssLinkQuery(result);
            return links;
            //try
            //{
            //    if (links.Count() > 0)
            //    {
            //        return links;
            //    }
            //}
            //catch
            //{
            //    return null;
            //}
            //return null;
        }

        public IEnumerable<Feed> GetFeedToUpdate(int minutes,int amount)
        {
            try
            {
                DateTime updateTime = DateTime.UtcNow.AddMinutes(-minutes);
                return GetFeedtoUpdate(updateTime,amount);
            }
            catch (ArgumentNullException)
            {
                return null;
            }
        }

        private IEnumerable<Feed> GetFeedtoUpdate(DateTime updateTime,int amount)
        {
            var result = from f in Feeds
                         where f.LastUpdateTime < updateTime
                         select f;
            IEnumerable<Feed> feeds = ProcessFeedsQuery(result).Take(amount);
            if (feeds.Count() == 0) return null;

            foreach (Feed f in feeds)
            {
                IEnumerable<RssLink> links = GetRssLinks(f.RowKey);
                if (links != null)
                {
                    foreach (RssLink r in links)
                    {
                        f.AddRssLink(r);
                    }
                }
                // ADDED.. BUG RSS COUNT = 0
                //UpdatedFeed(f);
            }
            return feeds;
        }

        public void UpdatedFeed(Feed f)
        {
            try
            {
                f.UpdateFeed();
                this.UpdateObject(f);
                this.SaveChanges();
            }
            catch (DataServiceRequestException e)
            {
                OperationResponse response = e.Response.First();
                if (response.StatusCode == (int)HttpStatusCode.PreconditionFailed)
                {
                    // query the object again to retrieve the latest etag 
                    // and update it
                }
            }
        }

        public IEnumerable<Feed> ProcessFeedsQuery(IQueryable<Feed> resultset)
        {
            TableStorageDataServiceQuery<Feed> query = new TableStorageDataServiceQuery<Feed>(resultset as DataServiceQuery<Feed>);
            IEnumerable<Feed> queryResults = query.ExecuteAllWithRetries();
            return queryResults;
        }

        public IEnumerable<RssLink> ProcessRssLinkQuery(IQueryable<RssLink> resultset)
        {
            TableStorageDataServiceQuery<RssLink> query = new TableStorageDataServiceQuery<RssLink>(resultset as DataServiceQuery<RssLink>);
            IEnumerable<RssLink> queryResults = query.ExecuteAllWithRetries();
            return queryResults;
        }
    }
}